package com.gitee.kamismile.stoneComEx.util;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.*;

/**
 * 一般加密解密工具<br>
 * DESede/DES/BlowFish<br>
 * DES的密钥(key)长度是为8个字节,加密解密的速度是最快的<br>
 * DESede的密钥(key)长度是24个字节<br>
 * BlowFish的密钥(key)是可变的 加密最快，强度最高,密钥长度范围(1 - 16)<br>
 *
 * @author songdawei
 * @version 1.0
 *  2008-10-20
 */
public class SecretCodeUtil {
    public final static String DES = "DES";
    public final static String DESEDE = "DESede";
    public final static String BLOWFISH = "BlowFish";
    public final static String MD5 = "MD5";

    /**
     * md5加密
     *
     * @param plainText 需要加密的原文
     * @return 加密后的字符串
     */
    public static String getMD5ofStr(String plainText) {
        try {
            return getMD5ofStr(string2Bytes(plainText));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 字节码加密
     *
     * @param str 原文的字节码
     * @return 加密后的字符串
     */
    public static String getMD5ofStr(byte str[]) {
        try {
            MessageDigest md = MessageDigest.getInstance(MD5);
            md.update(str);
            byte b[] = md.digest();
            return bytes2HexString(b);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 对数据源进行加密
     *
     * @param src  数据源
     * @param key  密钥
     * @param name 算法的名称
     * @return 返回加密后的数据
     * @throws Exception 异常
     */
    public static byte[] encrypt(byte[] src, byte[] key, String name)
            throws Exception {

        SecretKeySpec securekey = new SecretKeySpec(key, name);
        // Cipher对象实际完成加密操作
        Cipher cipher = Cipher.getInstance(name);
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.ENCRYPT_MODE, securekey);
        // 现在，获取数据并加密
        // 正式执行加密操作
        return cipher.doFinal(src);
    }

    /**
     * 对加密的数据源进行解密
     *
     * @param src  数据源
     * @param key  密钥
     * @param name 算法的名称
     * @return 返回解密后的原始数据
     * @throws Exception 异常
     */
    public static byte[] decrypt(byte[] src, byte[] key, String name)
            throws Exception {

        SecretKeySpec securekey = new SecretKeySpec(key, name);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance(name);
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey);
        // 现在，获取数据并解密
        // 正式执行解密操作
        return cipher.doFinal(src);
    }

    /**
     * 二行制转字符串
     *
     * @param bytes 二进制数据
     * @return 转换后的字符串
     */
    public static String bytes2HexString(byte[] bytes) {
        String hs = null;
        if (bytes != null) {
            final int size = bytes.length;
            if (size > 0) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < size; i++) {
                    String tmp = (Integer.toHexString(bytes[i] & 0XFF));
                    if (tmp.length() == 1) {
                        sb.append("0");
                        sb.append(tmp);
                    } else {
                        sb.append(tmp);
                    }
                }
                hs = sb.toString().toUpperCase();
            }
        }
        return hs;
    }

    public static byte[] hex2byte(byte[] b) {
        if ((b.length % 2) != 0) {
            return null;
        }
        byte[] b2 = new byte[b.length / 2];
        for (int n = 0; n < b.length; n += 2) {
            String item = new String(b, n, 2);
            b2[n / 2] = (byte) Integer.parseInt(item, 16);
        }
        return b2;
    }

    /**
     * 十六进位格式字符串转二进制流。
     *
     * @param hs String
     * @return byte[]
     */
    public static byte[] hexString2Bytes(String hs) {
        byte[] bytes = null;
        if (hs != null) {
            final int size = (hs.length()) / 2;
            if (size > 0) {
                bytes = new byte[size];
                for (int i = 0; i < size; i++) {
                    String hsByte = hs.substring(i * 2, i * 2 + 2);
                    byte b = 0;
                    try {
                        b = (byte) (Integer.parseInt(hsByte, 16));
                    } catch (NumberFormatException e) {
                        b = 0;
                    }
                    bytes[i] = b;
                }
            }
        }
        return bytes;
    }

    /**
     * 字符串解密
     *
     * @param data 字符串加密数据
     * @param key  密钥
     * @param name 算法名称
     * @return 解密后的字符串
     */
    public static String decrypt(String data, String key, String name) {
        try {
            return new String(decrypt(hex2byte(data.getBytes()),
                    string2Bytes(key), name));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 字符串解密
     *
     * @param data 字符串加密数据
     * @param key  密钥
     * @param name 算法名称
     * @return 解密后的字符串
     */
    public static String decrypt(String data, byte[] key, String name) {
        try {
            return new String(decrypt(hex2byte(data.getBytes()), key, name));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 把字符串转化成 Unicode Bytes.
     *
     * @param s String
     * @return byte[]
     */
    public static byte[] string2Bytes(String s) {
        byte[] bytes = null;
        if (s != null) {
            try {
                bytes = s.getBytes("utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }

    /**
     * 根据 Unicode Bytes 构造字符串.
     *
     * @param bytes byte[]
     * @return String
     */
    public static String bytes2String(byte[] bytes) {
        String s = null;
        if (bytes != null) {
            try {
                s = new String(bytes, "utf-8");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return s;
    }


    /**
     * 字符串加密
     *
     * @param data 字符串数据
     * @param key  密钥
     * @param name 算法名称
     * @return 加密后的字符串
     */
    public static String encrypt(String data, byte[] key, String name) {
        try {
            return bytes2HexString(encrypt(data.getBytes(), key, name));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 字符串加密
     *
     * @param data 字符串数据
     * @param key  密钥
     * @param name 算法名称
     * @return 加密后的字符串
     */
    public static String encrypt(String data, String key, String name) {
        try {
            return bytes2HexString(encrypt(data.getBytes(), string2Bytes(key), name));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static byte[] xorWithKey(byte[] b, byte[] key) {
        byte[] out = new byte[b.length];
        for (int i = 0; i < b.length; i++) {
            out[i] = (byte) (b[i] ^ key[i % key.length]);
        }
        return out;
    }


    public static String base64Encode(String data, String key) {
        byte[] encodeBase64 = Base64.encodeBase64(xorWithKey(data.getBytes(), key.getBytes()));
        return new String(encodeBase64);
    }

    public static String encrypt(String strOld, String strKey) {
        byte[] data = strOld.getBytes();
        byte[] keyData = strKey.getBytes();
        int keyIndex = 0;
        for (int x = 0; x < strOld.length(); x++) {
            data[x] = (byte) (data[x] ^ keyData[keyIndex]);
            if (++keyIndex == keyData.length) {
                keyIndex = 0;
            }
        }
        return new String(data);
    }

    public static String signSHA1(Map<String, Object> params, String SIGN_KEY, String signKey) throws Exception {
        params.put(SIGN_KEY, signKey);
        Map<String, String> needVerify = new HashMap<>();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            needVerify.put(entry.getKey(), String.valueOf(entry.getValue()));
        }
        List<Map.Entry<String, String>> entryList = new ArrayList<>(needVerify.entrySet());
        //排序
        Collections.sort(entryList, (o1, o2) -> o1.getKey().compareTo(o2.getKey()));
        StringBuilder buffer = new StringBuilder();
        for (Map.Entry<String, String> entry : entryList) {
            buffer.append(entry.getKey()).append(entry.getValue());
        }
        return DigestUtils.sha1Hex(buffer.toString());
    }
}
